package com.smile.commons.gps;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.smile.commons.gps.domain.*;
import com.smile.commons.gps.domain.kml.KmlParams;
import com.smile.commons.gps.domain.kml.RoutePointInfo;
import lombok.Data;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * WPMZ文件生成工具类
 * 基于面状航线数据生成包含waylines.wpml和template.kml的WPMZ文件夹结构
 * 
 * @author System
 * @since 2024-09-18
 */
public class WpmzFileGenerator {

    private static final String LOCAL_WPMZ_FILE_PATH = "file/wpmz/";
    private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    
    /**
     * WPMZ生成配置
     */
    @Data
    public static class WpmzConfig {
        /** 文件名（不含扩展名） */
        private String fileName;
        /**
         * 起飞点设置
         */
        private String takeOffRefPoint;
        /**
         * 图片存储
         */
        private String imageFormat;
        /** 飞行高度(米) */
        private BigDecimal flightHeight = new BigDecimal("100");
        
        /** 飞行速度(m/s) */
        private Double flightSpeed = 5.0;
        
        /** 过渡速度(m/s) */
        private BigDecimal transitionalSpeed = new BigDecimal("3.0");
        
        /** 返航高度(米) */
        private BigDecimal rthHeight = new BigDecimal("120");
        
        /** 起飞安全高度(米) */
        private BigDecimal takeOffSecurityHeight = new BigDecimal("80");
        
        /** 无人机类型枚举值 */
        private Integer droneEnumValue = 67;
        
        /** 无人机子类型枚举值 */
        private Integer droneSubEnumValue = 1;
        
        /** 负载类型枚举值 */
        private Integer payloadEnumValue = 99;
        
        /** 负载子类型枚举值 */
        private Integer payloadSubEnumValue = 2;
        
        /** 负载位置索引 */
        private Integer payloadPositionIndex = 0;
        
        /** 航点转弯模式 */
        private String waypointTurnMode = "toPointAndStopWithDiscontinuityCurvature";
        
        /** 航点偏航角模式 */
        private String waypointHeadingMode = "followWayline";
        
        /** 完成动作 */
        private String finishAction = "goHome";
        
        /** 失控动作 */
        private String exitOnRcLostAction = "goHome";
        
        /** 执行失控动作 */
        private String executeRcLostAction = "goBack";
        
        /** 飞向首航点模式 */
        private String flyToWaylineMode = "safely";
        
        /** 作者信息 */
        private String author = "WpmzFileGenerator";
        
        /** 创建时间戳 */
        private Long createTime = System.currentTimeMillis();
        
        /** 更新时间戳 */
        private Long updateTime = System.currentTimeMillis();
        
        /** 模板类型 */
        private String templateType = "mapping2d";
        
        /** 是否启用坐标系转换（GCJ02转WGS84） */
        private Boolean enableCoordinateConversion = true;
        
        /** 原始坐标系类型（GCJ02: 高德地图坐标系, WGS84: GPS坐标系, BD09: 百度坐标系） */
        private String sourceCoordinateSystem = "GCJ02";
        
        /** 目标坐标系类型（生成WPMZ文件时使用的坐标系，默认WGS84） */
        private String targetCoordinateSystem = "WGS84";

        private MappingTypeReq mappingTypeReq;

        /** 航向重叠率（百分比，如：80表示80%） */
        private Integer overlapH = 80;

        /** 旁向重叠率（百分比，如：60表示60%） */
        private Integer overlapW = 60;


        /** 航线方向（度，0-360） */
        private Integer direction = 0;

        /** 测区外扩距离（米） */
        private Integer margin = 50;

        /** 相机焦距（毫米） */
        private Double focalLength = 24.0;

        /** 传感器宽度（毫米） */
        private Double sensorWidth = 36.0;

        /** 传感器高度（毫米） */
        private Double sensorHeight = 24.0;

        /** 图像宽度（像素） */
        private Integer imageWidth = 4000;

        /** 图像高度（像素） */
        private Integer imageHeight = 3000;

    }
    
    /**
     * WPMZ生成结果
     */
    @Data
    public static class WpmzGenerationResult {
        /** 生成的WPMZ文件路径 */
        private String wpmzFilePath;
        
        /** 航点数量 */
        private Integer waypointCount;
        
        /** 预估飞行时间(分钟) */
        private Double estimatedFlightTime;
        
        /** 预估飞行距离(米) */
        private Double estimatedDistance;
        
        /** 生成摘要 */
        private String summary;
        
        /** 使用的配置 */
        private WpmzConfig usedConfig;
    }

    /**
     * 基于面状航线数据生成WPMZ文件（使用默认配置）
     * 
     * @param flightPath 航线路径点列表
     * @param fileName 输出文件名（不含扩展名）
     * @return WPMZ生成结果
     * @throws IOException 文件操作异常
     */
    public static WpmzGenerationResult generateWpmzFromFlightPath(
            List<CoordinatePointReq> flightPath, 
            String fileName) throws IOException {
        
        WpmzConfig defaultConfig = new WpmzConfig();
        defaultConfig.setFileName(fileName);
        return generateWpmzFromFlightPath(flightPath, defaultConfig);
    }

    /**
     * 基于面状航线数据和自定义配置生成WPMZ文件
     * 
     * @param flightPath 航线路径点列表
     * @param config WPMZ生成配置
     * @return WPMZ生成结果
     * @throws IOException 文件操作异常
     */
    public static WpmzGenerationResult generateWpmzFromFlightPath(
            List<CoordinatePointReq> flightPath, 
            WpmzConfig config) throws IOException {
        
        System.out.println("=== 开始生成WPMZ文件 ===");
        System.out.println("配置文件名: " + config.getFileName());
        System.out.println("航点数量: " + flightPath.size());
        
        // 1. 验证输入参数
        validateInputs(flightPath, config);
        
        // 2. 创建KML参数
        KmlParams kmlParams = createKmlParams(flightPath, config);
        
        // 3. 生成WPMZ文件
        String wpmzPath = generateWpmzFile(config.getFileName(), kmlParams, config);
        
        // 4. 计算统计信息
        WpmzGenerationResult result = calculateStatistics(wpmzPath, flightPath, config);
        
        System.out.println("WPMZ文件生成完成: " + result.getSummary());
        return result;
    }

    /**
     * 基于PlanarAirlineService生成结果直接生成WPMZ文件
     * 
     * @param airlineResult 面状航线生成结果
     * @param fileName 输出文件名
     * @return WPMZ生成结果
     * @throws IOException 文件操作异常
     * @deprecated 建议使用 generateWpmzFromAirlineResultWithBoundary 方法，传入原始边界数据
     */
    public static WpmzGenerationResult generateWpmzFromAirlineResult(
            PlanarAirlineService.PlanarAirlineResult airlineResult,
            String fileName) throws IOException {
        
        return generateWpmzFromFlightPath(airlineResult.getFlightPath(), fileName);
    }
    
    /**
     * 基于面状航线生成结果和原始边界数据生成WPMZ文件（推荐方法）
     * 
     * @param airlineResult 面状航线生成结果
     * @param originalBoundary 原始边界数据（用于生成正确的测区边框）
     * @param fileName 输出文件名
     * @return WPMZ生成结果
     * @throws IOException 文件操作异常
     */
    public static WpmzGenerationResult generateWpmzFromAirlineResultWithBoundary(
            PlanarAirlineService.PlanarAirlineResult airlineResult,
            List<CoordinatePointReq> originalBoundary,
            String fileName) throws IOException {
        
        WpmzConfig config = new WpmzConfig();
        config.setFileName(fileName);
        return generateWpmzFromAirlineResultWithBoundary(airlineResult, originalBoundary, config);
    }
    



    public static WpmzGenerationResult generateWpmzFromAirlineResultWithBoundary(
            PlanarAirlineService.PlanarAirlineResult airlineResult,
            List<CoordinatePointReq> originalBoundary,
            WpmzConfig config,KmlParams originalKmlParams) throws IOException {

        System.out.println("=== 开始生成WPMZ文件（使用原始边界数据）===");
        System.out.println("配置文件名: " + config.getFileName());
        System.out.println("航点数量: " + airlineResult.getFlightPath().size());
        System.out.println("边界点数量: " + originalBoundary.size());

        // 1. 验证输入参数
        validateInputsWithBoundary(airlineResult, originalBoundary, config);

        // 2. 创建KML参数（使用原始边界数据）
        KmlParams kmlParams = createKmlParamsWithBoundary(airlineResult.getFlightPath(), originalBoundary, config,originalKmlParams);
        System.out.println("kml参数："+JSON.toJSONString(kmlParams));

        // 3. 生成WPMZ文件
        String wpmzPath = generateWpmzFile(config.getFileName(), kmlParams, config);

        // 4. 计算统计信息
        WpmzGenerationResult result = calculateStatistics(wpmzPath, airlineResult.getFlightPath(), config);

        System.out.println("WPMZ文件生成完成（使用原始边界）: " + result.getSummary());
        return result;
    }

    public static WpmzGenerationResult generateWpmzFromAirlineResultWithBoundary(
            PlanarAirlineService.PlanarAirlineResult airlineResult,
            List<CoordinatePointReq> originalBoundary,
            WpmzConfig config) throws IOException {

        System.out.println("=== 开始生成WPMZ文件（使用原始边界数据）===");
        System.out.println("配置文件名: " + config.getFileName());
        System.out.println("航点数量: " + airlineResult.getFlightPath().size());
        System.out.println("边界点数量: " + originalBoundary.size());

        // 1. 验证输入参数
        validateInputsWithBoundary(airlineResult, originalBoundary, config);

        // 2. 创建KML参数（使用原始边界数据）
        KmlParams kmlParams = createKmlParamsWithBoundary(airlineResult.getFlightPath(), originalBoundary, config);
        System.out.println("kml参数："+JSON.toJSONString(kmlParams));

        // 3. 生成WPMZ文件
        String wpmzPath = generateWpmzFile(config.getFileName(), kmlParams, config);

        // 4. 计算统计信息
        WpmzGenerationResult result = calculateStatistics(wpmzPath, airlineResult.getFlightPath(), config);

        System.out.println("WPMZ文件生成完成（使用原始边界）: " + result.getSummary());
        return result;
    }
    /**
     * 验证输入参数
     */
    private static void validateInputs(List<CoordinatePointReq> flightPath, WpmzConfig config) {
        if (flightPath == null || flightPath.isEmpty()) {
            throw new IllegalArgumentException("航线路径点列表不能为空");
        }
        
        if (config == null) {
            throw new IllegalArgumentException("WPMZ配置不能为空");
        }
        
        if (config.getFileName() == null || config.getFileName().trim().isEmpty()) {
            throw new IllegalArgumentException("输出文件名不能为空");
        }
        
        // 验证航点的有效性
        for (CoordinatePointReq point : flightPath) {
            if (point.getLatitude() == null || point.getLongitude() == null) {
                throw new IllegalArgumentException("航点坐标不能为空");
            }
        }
    }
    
    /**
     * 验证带边界数据的输入参数
     */
    private static void validateInputsWithBoundary(
            PlanarAirlineService.PlanarAirlineResult airlineResult,
            List<CoordinatePointReq> originalBoundary, 
            WpmzConfig config) {
        
        if (airlineResult == null || airlineResult.getFlightPath() == null || airlineResult.getFlightPath().isEmpty()) {
            throw new IllegalArgumentException("航线生成结果或航点数据不能为空");
        }
        
        if (originalBoundary == null || originalBoundary.size() < 3) {
            throw new IllegalArgumentException("原始边界数据不能为空，且至少需要3个点构成多边形");
        }
        
        if (config == null) {
            throw new IllegalArgumentException("WPMZ配置不能为空");
        }
        
        if (config.getFileName() == null || config.getFileName().trim().isEmpty()) {
            throw new IllegalArgumentException("输出文件名不能为空");
        }
        
        // 验证边界点的有效性
        for (CoordinatePointReq point : originalBoundary) {
            if (point.getLatitude() == null || point.getLongitude() == null) {
                throw new IllegalArgumentException("边界点坐标不能为空");
            }
        }
        
        // 验证航点的有效性
        for (CoordinatePointReq point : airlineResult.getFlightPath()) {
            if (point.getLatitude() == null || point.getLongitude() == null) {
                throw new IllegalArgumentException("航点坐标不能为空");
            }
        }
    }

    /**
     * 创建KML参数
     */
    private static KmlParams createKmlParams(List<CoordinatePointReq> flightPath, WpmzConfig config) {
        KmlParams kmlParams = new KmlParams();
        
        // 设置基本参数
        kmlParams.setAutoFlightSpeed(new BigDecimal(config.getFlightSpeed()));
        kmlParams.setGlobalHeight(config.getFlightHeight());
        kmlParams.setTemplateType(config.getTemplateType());
        kmlParams.setFinishAction(config.getFinishAction());
        kmlParams.setExitOnRcLostAction(config.getExitOnRcLostAction());
        
        // 设置必需字段（避免空指针异常）
        kmlParams.setAirlineHeightType(0); // 相对起飞点高度
        kmlParams.setDroneType(config.getDroneEnumValue());
        kmlParams.setSubDroneType(config.getDroneSubEnumValue());
        kmlParams.setPayloadType(config.getPayloadEnumValue());
        kmlParams.setPayloadPosition(config.getPayloadPositionIndex());
        kmlParams.setGlobalShootHeight(config.getFlightHeight());
        
        // 初始化航点转弯参数
        WaypointTurnReq waypointTurnReq = new WaypointTurnReq();
        waypointTurnReq.setWaypointTurnMode(config.getWaypointTurnMode());
        waypointTurnReq.setUseStraightLine(1); // 航段轨迹尽量贴合两点连线
        waypointTurnReq.setWaypointTurnDampingDist(1.0); // 默认转弯截距
        kmlParams.setWaypointTurnReq(waypointTurnReq);
        
        // 初始化航点偏航角参数
        WaypointHeadingReq waypointHeadingReq = new WaypointHeadingReq();
        waypointHeadingReq.setWaypointHeadingMode(config.getWaypointHeadingMode());
        kmlParams.setWaypointHeadingReq(waypointHeadingReq);
        
        // 区分面状航线和线状航线的处理
        if ("mapping2d".equals(config.getTemplateType()) || "mapping3d".equals(config.getTemplateType()) || "mappingStrip".equals(config.getTemplateType())) {
            // 面状航线：使用边界多边形，航点数据会在系统内部自动生成
            setupMappingParameters(kmlParams, flightPath, config);
        } else {
            // 线状航线：直接使用航点列表
            List<RoutePointInfo> routePoints = convertToRoutePoints(flightPath, config);
            kmlParams.setRoutePointList(routePoints);
        }
        
        return kmlParams;
    }
    
    /**
     * 创建KML参数（使用原始边界数据）
     */
    private static KmlParams createKmlParamsWithBoundary(
            List<CoordinatePointReq> flightPath, 
            List<CoordinatePointReq> originalBoundary,
            WpmzConfig config,KmlParams  originalKmlParams) {
        
        KmlParams kmlParams = BeanUtil.copyProperties(originalKmlParams, KmlParams.class);
        
        // 设置基本参数
        kmlParams.setAutoFlightSpeed(new BigDecimal(config.getFlightSpeed()));
        kmlParams.setGlobalHeight(config.getFlightHeight());
        kmlParams.setTemplateType(config.getTemplateType());
        kmlParams.setFinishAction(config.getFinishAction());
        kmlParams.setExitOnRcLostAction(config.getExitOnRcLostAction());
        kmlParams.setImageFormat(config.getImageFormat());
        // 设置必需字段（避免空指针异常）
        kmlParams.setAirlineHeightType(0); // 相对起飞点高度
        kmlParams.setDroneType(config.getDroneEnumValue());
        kmlParams.setSubDroneType(config.getDroneSubEnumValue());
        kmlParams.setPayloadType(config.getPayloadEnumValue());
        kmlParams.setPayloadPosition(config.getPayloadPositionIndex());
        kmlParams.setGlobalShootHeight(config.getFlightHeight());
        
        // 初始化航点转弯参数
        WaypointTurnReq waypointTurnReq = new WaypointTurnReq();
        waypointTurnReq.setWaypointTurnMode(config.getWaypointTurnMode());
        waypointTurnReq.setUseStraightLine(1); // 航段轨迹尽量贴合两点连线
        waypointTurnReq.setWaypointTurnDampingDist(1.0); // 默认转弯截距
        kmlParams.setWaypointTurnReq(waypointTurnReq);

        kmlParams.setTakeOffRefPoint(config.getTakeOffRefPoint());
        // 初始化航点偏航角参数
        WaypointHeadingReq waypointHeadingReq = new WaypointHeadingReq();
        waypointHeadingReq.setWaypointHeadingMode(config.getWaypointHeadingMode());
        kmlParams.setWaypointHeadingReq(waypointHeadingReq);
        
        // 区分面状航线和线状航线的处理
        if ("mapping2d".equals(config.getTemplateType()) || "mapping3d".equals(config.getTemplateType()) || "mappingStrip".equals(config.getTemplateType())) {
            // 面状航线：使用原始边界数据（这是关键修复）
            setupMappingParametersWithBoundary(kmlParams, flightPath, originalBoundary, config);
//            MappingTypeReq mappingTypeReq = new MappingTypeReq();
//            mappingTypeReq.setOverlapH(config.getOverlapH());
//            mappingTypeReq.setOverlapW(config.getOverlapW());
//            mappingTypeReq.setOrthoCameraOverlapH(config.getOverlapH());
//            mappingTypeReq.setOrthoCameraOverlapW(config.getOverlapW());
//            mappingTypeReq.setInclinedCameraOverlapH(config.getOverlapH());
//            mappingTypeReq.setInclinedCameraOverlapW(config.getOverlapW());
//
//            kmlParams.setMappingTypeReq(mappingTypeReq);
        } else {
            // 线状航线：直接使用航点列表
            List<RoutePointInfo> routePoints = convertToRoutePoints(flightPath, config);
            kmlParams.setRoutePointList(routePoints);
        }
        
        return kmlParams;
    }
    /**
     * 创建KML参数（使用原始边界数据）
     */
    private static KmlParams createKmlParamsWithBoundary(
            List<CoordinatePointReq> flightPath,
            List<CoordinatePointReq> originalBoundary,
            WpmzConfig config) {

        KmlParams kmlParams = new KmlParams();

        // 设置基本参数
        kmlParams.setAutoFlightSpeed(new BigDecimal(config.getFlightSpeed()));
        kmlParams.setGlobalHeight(config.getFlightHeight());
        kmlParams.setTemplateType(config.getTemplateType());
        kmlParams.setFinishAction(config.getFinishAction());
        kmlParams.setExitOnRcLostAction(config.getExitOnRcLostAction());
        kmlParams.setImageFormat(config.getImageFormat());
        // 设置必需字段（避免空指针异常）
        kmlParams.setAirlineHeightType(0); // 相对起飞点高度
        kmlParams.setDroneType(config.getDroneEnumValue());
        kmlParams.setSubDroneType(config.getDroneSubEnumValue());
        kmlParams.setPayloadType(config.getPayloadEnumValue());
        kmlParams.setPayloadPosition(config.getPayloadPositionIndex());
        kmlParams.setGlobalShootHeight(config.getFlightHeight());

        // 初始化航点转弯参数
        WaypointTurnReq waypointTurnReq = new WaypointTurnReq();
        waypointTurnReq.setWaypointTurnMode(config.getWaypointTurnMode());
        waypointTurnReq.setUseStraightLine(1); // 航段轨迹尽量贴合两点连线
        waypointTurnReq.setWaypointTurnDampingDist(1.0); // 默认转弯截距
        kmlParams.setWaypointTurnReq(waypointTurnReq);

        kmlParams.setTakeOffRefPoint(config.getTakeOffRefPoint());
        // 初始化航点偏航角参数
        WaypointHeadingReq waypointHeadingReq = new WaypointHeadingReq();
        waypointHeadingReq.setWaypointHeadingMode(config.getWaypointHeadingMode());
        kmlParams.setWaypointHeadingReq(waypointHeadingReq);

        // 区分面状航线和线状航线的处理
        if ("mapping2d".equals(config.getTemplateType()) || "mapping3d".equals(config.getTemplateType()) || "mappingStrip".equals(config.getTemplateType())) {
            // 面状航线：使用原始边界数据（这是关键修复）
            setupMappingParametersWithBoundary(kmlParams, flightPath, originalBoundary, config);
//            MappingTypeReq mappingTypeReq = new MappingTypeReq();
//            mappingTypeReq.setOverlapH(config.getOverlapH());
//            mappingTypeReq.setOverlapW(config.getOverlapW());
//            mappingTypeReq.setOrthoCameraOverlapH(config.getOverlapH());
//            mappingTypeReq.setOrthoCameraOverlapW(config.getOverlapW());
//            mappingTypeReq.setInclinedCameraOverlapH(config.getOverlapH());
//            mappingTypeReq.setInclinedCameraOverlapW(config.getOverlapW());
//
//            kmlParams.setMappingTypeReq(mappingTypeReq);
        } else {
            // 线状航线：直接使用航点列表
            List<RoutePointInfo> routePoints = convertToRoutePoints(flightPath, config);
            kmlParams.setRoutePointList(routePoints);
        }

        return kmlParams;
    }
    /**
     * 设置面状航线的建图参数
     */
    private static void setupMappingParameters(KmlParams kmlParams, List<CoordinatePointReq> flightPath, WpmzConfig config) {
        // 初始化建图航拍参数
        MappingTypeReq mappingTypeReq = new MappingTypeReq();
        mappingTypeReq.setCollectionMethod("ortho"); // 正射采集
        mappingTypeReq.setLensType("camera"); // 相机镜头
        mappingTypeReq.setOverlapH(80); // 航向重叠率80%
        mappingTypeReq.setOverlapW(70); // 旁向重叠率70%
        mappingTypeReq.setElevationOptimizeEnable(1); // 开启高程优化（面状航线推荐）
        mappingTypeReq.setSmartObliqueEnable(0); // 智能倾斜摄影
        mappingTypeReq.setQuickOrthoMappingEnable(0); // 快拼模式
        mappingTypeReq.setFacadeWaylineEnable(0); // 立面航线
        mappingTypeReq.setIsLookAtSceneSet(0); // 是否设置看向场景
        mappingTypeReq.setShootType("time"); // 等时间拍照
        mappingTypeReq.setDirection("93"); // 航线方向（与示例保持一致）
        mappingTypeReq.setMargin("0"); // 测区外扩距离（与示例保持一致）
        mappingTypeReq.setEfficiencyFlightModeEnable(0); // 效率飞行模式
        mappingTypeReq.setCaliFlightEnable(0); // 标定飞行
        
        // 从航线路径提取边界多边形（这是面状航线的关键）
        List<CoordinatePointReq> boundaryPolygon = extractBoundaryFromFlightPath(flightPath);
        
        // 如果启用了坐标系转换，将边界数据转换为WGS84
        if (config.getEnableCoordinateConversion() != null && config.getEnableCoordinateConversion()) {
            System.out.println("ℹ️ 开始转换提取的边界坐标系: " + config.getSourceCoordinateSystem() + " -> " + config.getTargetCoordinateSystem());
            boundaryPolygon = convertCoordinateSystemBatch(
                boundaryPolygon, 
                config.getSourceCoordinateSystem(), 
                config.getTargetCoordinateSystem()
            );
        }
        
        mappingTypeReq.setCoordinates(boundaryPolygon);
        
        // 设置重叠率参数
        mappingTypeReq.setOrthoCameraOverlapH(80);
        mappingTypeReq.setOrthoCameraOverlapW(70);
        mappingTypeReq.setInclinedCameraOverlapH(80);
        mappingTypeReq.setInclinedCameraOverlapW(70);
        
        kmlParams.setMappingTypeReq(mappingTypeReq);
        
        // 对于面状航线，不需要设置具体的RoutePointList
        // 系统会根据边界多边形和参数自动生成航点
//        kmlParams.setRoutePointList(new ArrayList<>());
        // 对于面状航线，我们也需要设置实际生成的航点列表
        // 转换航点数据格式并添加到kmlParams中
        List<RoutePointInfo> routePoints = convertToRoutePoints(flightPath, config);
        kmlParams.setRoutePointList(routePoints);
        if (config.getEnableCoordinateConversion() != null && config.getEnableCoordinateConversion()) {
            System.out.println("✓ 已应用坐标系转换（提取的边界）: " + config.getSourceCoordinateSystem() + " -> " + config.getTargetCoordinateSystem());
        }
    }
    
    /**
     * 设置面状航线的建图参数（使用原始边界数据）
     */
    private static void setupMappingParametersWithBoundary(
            KmlParams kmlParams, 
            List<CoordinatePointReq> flightPath,
            List<CoordinatePointReq> originalBoundary,
            WpmzConfig config) {
        
        // 初始化建图航拍参数
//        MappingTypeReq mappingTypeReq = new MappingTypeReq();
        MappingTypeReq mappingTypeReq = config.mappingTypeReq;
        if (mappingTypeReq == null) {
            mappingTypeReq = new MappingTypeReq();
            mappingTypeReq.setCollectionMethod("ortho");
            mappingTypeReq.setOverlapH(80); // 航向重叠率80%
            mappingTypeReq.setOverlapW(70); // 旁向重叠率70%
            mappingTypeReq.setElevationOptimizeEnable(1); // 开启高程优化（面状航线推荐）
            mappingTypeReq.setSmartObliqueEnable(0); // 智能倾斜摄影
            mappingTypeReq.setQuickOrthoMappingEnable(0); // 快拼模式
            mappingTypeReq.setFacadeWaylineEnable(0); // 立面航线
            mappingTypeReq.setIsLookAtSceneSet(0); // 是否设置看向场景
            mappingTypeReq.setShootType("time"); // 等时间拍照
            mappingTypeReq.setDirection("93"); // 航线方向（与示例保持一致）
        }else{
            mappingTypeReq.setCollectionMethod(mappingTypeReq.getCollectionMethod()); // 正射采集

        }
        mappingTypeReq.setLensType("camera"); // 相机镜头
        mappingTypeReq.setElevationOptimizeEnable(1); // 开启高程优化（面状航线推荐）
        mappingTypeReq.setSmartObliqueEnable(0); // 智能倾斜摄影
        mappingTypeReq.setQuickOrthoMappingEnable(0); // 快拼模式
        mappingTypeReq.setFacadeWaylineEnable(0); // 立面航线
        mappingTypeReq.setIsLookAtSceneSet(0); // 是否设置看向场景
//        mappingTypeReq.setShootType("time"); // 等时间拍照
//        mappingTypeReq.setDirection("93"); // 航线方向（与示例保持一致）
        mappingTypeReq.setMargin("0"); // 测区外扩距离（与示例保持一致）
        mappingTypeReq.setEfficiencyFlightModeEnable(0); // 效率飞行模式
        mappingTypeReq.setCaliFlightEnable(0); // 标定飞行
        
        // 处理原始边界数据（包括坐标转换）
        List<CoordinatePointReq> actualBoundary = originalBoundary;
        
        // 如果启用了坐标系转换，将边界数据转换为WGS84
        if (config.getEnableCoordinateConversion() != null && config.getEnableCoordinateConversion()) {
            System.out.println("ℹ️ 开始转换边界坐标系: " + config.getSourceCoordinateSystem() + " -> " + config.getTargetCoordinateSystem());
            actualBoundary = convertCoordinateSystemBatch(
                originalBoundary, 
                config.getSourceCoordinateSystem(), 
                config.getTargetCoordinateSystem()
            );
        }
        
        // 确保边界闭合
        actualBoundary = ensureBoundaryClosure(actualBoundary);
        mappingTypeReq.setCoordinates(actualBoundary);
        
        // 设置重叠率参数
        mappingTypeReq.setOrthoCameraOverlapH(config.getOverlapH());
        mappingTypeReq.setOrthoCameraOverlapW(config.getOverlapW());
        mappingTypeReq.setInclinedCameraOverlapH(config.getOverlapH());
        mappingTypeReq.setInclinedCameraOverlapW(config.getOverlapW());
        mappingTypeReq.setOverlapH(config.getOverlapH());
        mappingTypeReq.setOverlapW(config.getOverlapW());
        kmlParams.setMappingTypeReq(mappingTypeReq);
        
        // 对于面状航线，不需要设置具体的RoutePointList
        // 系统会根据边界多边形和参数自动生成航点
//        kmlParams.setRoutePointList(new ArrayList<>());
        // 对于面状航线，我们也需要设置实际生成的航点列表
        // 转换航点数据格式并添加到kmlParams中
        List<RoutePointInfo> routePoints = convertToRoutePoints(flightPath, config);
        kmlParams.setRoutePointList(routePoints);
        System.out.println("✓ 使用原始边界数据设置面状航线参数，边界点数: " + actualBoundary.size());
        if (config.getEnableCoordinateConversion() != null && config.getEnableCoordinateConversion()) {
            System.out.println("✓ 已应用坐标系转换: " + config.getSourceCoordinateSystem() + " -> " + config.getTargetCoordinateSystem());
        }
    }

    /**
     * 转换航点数据格式
     */
    private static List<RoutePointInfo> convertToRoutePoints(List<CoordinatePointReq> flightPath, WpmzConfig config) {
        List<RoutePointInfo> routePoints = new ArrayList<>();
        
        // 如果启用了坐标系转换，先转换航点坐标系
        List<CoordinatePointReq> actualFlightPath = flightPath;
        if (config.getEnableCoordinateConversion() != null && config.getEnableCoordinateConversion()) {
            System.out.println("ℹ️ 开始转换航点坐标系: " + config.getSourceCoordinateSystem() + " -> " + config.getTargetCoordinateSystem());
            actualFlightPath = convertCoordinateSystemBatch(
                flightPath, 
                config.getSourceCoordinateSystem(), 
                config.getTargetCoordinateSystem()
            );
        }
        
        for (int i = 0; i < actualFlightPath.size(); i++) {
            CoordinatePointReq point = actualFlightPath.get(i);
            RoutePointInfo routePoint = new RoutePointInfo();
            
            routePoint.setRoutePointIndex(i);
            routePoint.setLatitude(point.getLatitude().doubleValue());
            routePoint.setLongitude(point.getLongitude().doubleValue());
            routePoint.setHeight(point.getHeight());
            routePoint.setSpeed(config.getFlightSpeed());
//            routePoint.setUseGlobalHeight("false");
//            routePoint.setUseGlobalSpeed("false");
            
            // 根据航点位置添加特殊动作
            if (i == 0) {
                // 起始点：起飞动作
                addTakeoffActions(routePoint);
            } else if (i == actualFlightPath.size() - 1) {
                // 终点：拍照并准备返航
                addLandingActions(routePoint);
            } else {
                // 中间点：拍照动作
                addPhotoActions(routePoint);
            }
            
            routePoints.add(routePoint);
        }
        
        if (config.getEnableCoordinateConversion() != null && config.getEnableCoordinateConversion()) {
            System.out.println("✓ 已应用坐标系转换（航点）: " + config.getSourceCoordinateSystem() + " -> " + config.getTargetCoordinateSystem());
        }
        
        return routePoints;
    }

    /**
     * 添加起飞动作
     */
    private static void addTakeoffActions(RoutePointInfo routePoint) {
        List<PointActionReq> actions = new ArrayList<>();
        
        // 可以添加具体的起飞动作配置
        // 例如：相机设置、云台角度等
        
        routePoint.setActions(actions);
    }

    /**
     * 添加拍照动作
     */
    private static void addPhotoActions(RoutePointInfo routePoint) {
        List<PointActionReq> actions = new ArrayList<>();
        
        // 可以添加具体的拍照动作配置
        // 例如：拍照、悬停时间等
        
        routePoint.setActions(actions);
    }

    /**
     * 添加降落动作
     */
    private static void addLandingActions(RoutePointInfo routePoint) {
        List<PointActionReq> actions = new ArrayList<>();
        
        // 可以添加具体的降落前动作配置
        // 例如：最后拍照、云台归中等
        
        routePoint.setActions(actions);
    }



    /**
     * 生成WPMZ文件
     */
    private static String generateWpmzFile(String fileName, KmlParams kmlParams, WpmzConfig config) throws IOException {
        // 创建扩展参数
        RouteFileUtils.KmlParamsExtension extension = new RouteFileUtils.KmlParamsExtension();
        extension.setGlobalTransitionalSpeed(config.getTransitionalSpeed());
        extension.setGlobalRTHHeight(config.getRthHeight());
        extension.setTakeOffSecurityHeight(config.getTakeOffSecurityHeight());

        // 设置创建和更新时间
        extension.setCreateTime(config.getCreateTime());
        extension.setUpdateTime(config.getUpdateTime());
        extension.setAuthor(config.getAuthor());

        // 生成最终文件名
        String finalFileName = fileName + "_wpmz_" + System.currentTimeMillis();

        // 使用现有的KMZ生成方法，它会创建wpmz文件夹结构
        return RouteFileUtils.buildKmz(extension, finalFileName, kmlParams);
    }

    /**
     * 计算统计信息
     */
    private static WpmzGenerationResult calculateStatistics(String wpmzPath, 
                                                           List<CoordinatePointReq> flightPath, 
                                                           WpmzConfig config) {
        WpmzGenerationResult result = new WpmzGenerationResult();
        result.setWpmzFilePath(wpmzPath);
        result.setWaypointCount(flightPath.size());
        result.setUsedConfig(config);
        
        // 计算飞行距离
        double totalDistance = calculateTotalDistance(flightPath);
        result.setEstimatedDistance(totalDistance);
        
        // 计算飞行时间（距离/速度 + 悬停时间）
        double flightTime = (totalDistance / config.getFlightSpeed()) / 60.0; // 转换为分钟
        result.setEstimatedFlightTime(flightTime);
        
        // 生成摘要
        String summary = String.format(
            "WPMZ文件生成完成 - 航点数:%d, 距离:%.0fm, 时间:%.1fmin", 
            result.getWaypointCount(), 
            result.getEstimatedDistance(), 
            result.getEstimatedFlightTime()
        );
        result.setSummary(summary);
        
        return result;
    }

    /**
     * 计算航线总距离
     */
    private static double calculateTotalDistance(List<CoordinatePointReq> flightPath) {
        if (flightPath.size() < 2) return 0;
        
        double totalDistance = 0;
        for (int i = 1; i < flightPath.size(); i++) {
            totalDistance += calculateDistance(flightPath.get(i-1), flightPath.get(i));
        }
        return totalDistance;
    }

    /**
     * 计算两点距离（哈弗辛公式）
     */
    private static double calculateDistance(CoordinatePointReq point1, CoordinatePointReq point2) {
        double lat1 = Math.toRadians(point1.getLatitude().doubleValue());
        double lon1 = Math.toRadians(point1.getLongitude().doubleValue());
        double lat2 = Math.toRadians(point2.getLatitude().doubleValue());
        double lon2 = Math.toRadians(point2.getLongitude().doubleValue());
        
        double deltaLat = lat2 - lat1;
        double deltaLon = lon2 - lon1;
        
        double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
                   Math.cos(lat1) * Math.cos(lat2) *
                   Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        
        return 6378137.0 * c; // 地球半径 * 弧度
    }

    /**
     * 演示方法：展示WPMZ文件生成的使用方法
     */
    public static void demonstrateWpmzGeneration() {
        System.out.println("=== WPMZ文件生成演示 ===");
        
        try {
            // 1. 创建示例边界点（杭州西湖区域）
            List<CoordinatePointReq> boundaryPoints = createSampleBoundary();
            
            // 2. 生成面状航线
            PlanarAirlineGenerator.AirlineConfig airlineConfig = new PlanarAirlineGenerator.AirlineConfig();
            airlineConfig.setFlightHeight(new BigDecimal("100"));
            airlineConfig.setOverlapH(80);
            airlineConfig.setOverlapW(70);
            airlineConfig.setDirection(0);
            airlineConfig.setMargin(30);
            
            PlanarAirlineService.PlanarAirlineResult airlineResult = 
                PlanarAirlineService.generateCompletePlanarAirline(boundaryPoints, airlineConfig, 15.0);
            
            System.out.println("生成的航线数据:");
            System.out.println(JSONObject.toJSONString(airlineResult.getFlightPath()));
            
            // 3. 演示1：使用默认配置生成WPMZ
            System.out.println("\n1. 使用默认配置生成WPMZ文件");
            WpmzGenerationResult result1 = generateWpmzFromFlightPath(
                airlineResult.getFlightPath(), "sample_default_wpmz");
            System.out.println("结果: " + result1.getSummary());
            
            // 4. 演示2：使用自定义配置生成WPMZ
            System.out.println("\n2. 使用自定义配置生成WPMZ文件");
            WpmzConfig customConfig = new WpmzConfig();
            customConfig.setFileName("sample_custom_wpmz");
            customConfig.setFlightHeight(new BigDecimal("80"));
            customConfig.setFlightSpeed(8.0);
            customConfig.setDroneEnumValue(100); // 不同的无人机型号
            customConfig.setAuthor("CustomUser");
            
            WpmzGenerationResult result2 = generateWpmzFromFlightPath(
                airlineResult.getFlightPath(), customConfig);
            System.out.println("结果: " + result2.getSummary());
            
            // 5. 演示3：直接从AirlineResult生成
            System.out.println("\n3. 直接从AirlineResult生成WPMZ文件");
            WpmzGenerationResult result3 = generateWpmzFromAirlineResult(
                airlineResult, "sample_direct_wpmz");
            System.out.println("结果: " + result3.getSummary());
            
        } catch (Exception e) {
            System.err.println("演示失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 创建示例边界点
     */
    private static List<CoordinatePointReq> createSampleBoundary() {
        List<CoordinatePointReq> points = new ArrayList<>();
        
        // 杭州西湖附近的示例区域
        points.add(createPoint(30.250000, 120.140000));
        points.add(createPoint(30.250000, 120.150000));
        points.add(createPoint(30.259000, 120.150000));
        points.add(createPoint(30.259000, 120.140000));
        
        return points;
    }

    /**
     * 创建坐标点
     */
    private static CoordinatePointReq createPoint(double lat, double lon) {
        CoordinatePointReq point = new CoordinatePointReq();
        point.setLatitude(new BigDecimal(lat));
        point.setLongitude(new BigDecimal(lon));
        point.setHeight(new BigDecimal("120"));
        return point;
    }

    /**
     * 主方法：用于测试
     */
    public static void main(String[] args) {
        demonstrateWpmzGeneration();
    }
    
    /**
     * 从航线路径提取边界多边形
     * 面状航线的核心：使用实际的测区边界而不是航点列表
     */
    private static List<CoordinatePointReq> extractBoundaryFromFlightPath(List<CoordinatePointReq> flightPath) {
        if (flightPath == null || flightPath.size() < 3) {
            return new ArrayList<>();
        }
        
        // 对于面状航线，我们需要实际的测区边界，而不是生成的航点
        // 这里使用凸包算法或者简化的边界提取
        // 注意：示例template.kml中的边界是实际的多边形边界，不是航点列表
        
        // 使用Graham扫描算法计算凸包作为边界
        List<CoordinatePointReq> convexHull = calculateConvexHull(flightPath);
        
        // 如果凸包点数太少，使用简化的矩形边界
        if (convexHull.size() < 4) {
            return calculateBoundingRectangle(flightPath);
        }
        
        return convexHull;
    }
    
    /**
     * 计算凸包边界
     */
    private static List<CoordinatePointReq> calculateConvexHull(List<CoordinatePointReq> points) {
        if (points.size() < 3) {
            return new ArrayList<>(points);
        }
        
        // 找到最左下角的点
        CoordinatePointReq start = points.stream()
            .min((p1, p2) -> {
                int latCompare = p1.getLatitude().compareTo(p2.getLatitude());
                if (latCompare != 0) return latCompare;
                return p1.getLongitude().compareTo(p2.getLongitude());
            })
            .orElse(points.get(0));
        
        // 简化的凸包算法：找到边界上的关键点
        List<CoordinatePointReq> hull = new ArrayList<>();
        
        // 获取边界坐标范围
        double minLat = points.stream().mapToDouble(p -> p.getLatitude().doubleValue()).min().orElse(0);
        double maxLat = points.stream().mapToDouble(p -> p.getLatitude().doubleValue()).max().orElse(0);
        double minLon = points.stream().mapToDouble(p -> p.getLongitude().doubleValue()).min().orElse(0);
        double maxLon = points.stream().mapToDouble(p -> p.getLongitude().doubleValue()).max().orElse(0);
        
        // 创建凸包的五个关键点（参考示例template.kml的结构）
        hull.add(createCoordinatePoint(minLat, minLon, 0));
        hull.add(createCoordinatePoint(minLat, maxLon, 0));
        hull.add(createCoordinatePoint(maxLat, maxLon, 0));
        hull.add(createCoordinatePoint(maxLat, minLon, 0));
        hull.add(createCoordinatePoint(minLat, minLon, 0)); // 闭合多边形
        
        return hull;
    }
    
    /**
     * 计算矩形边界
     */
    private static List<CoordinatePointReq> calculateBoundingRectangle(List<CoordinatePointReq> flightPath) {
        // 找到最大和最小的经纬度
        double minLat = flightPath.stream().mapToDouble(p -> p.getLatitude().doubleValue()).min().orElse(0);
        double maxLat = flightPath.stream().mapToDouble(p -> p.getLatitude().doubleValue()).max().orElse(0);
        double minLon = flightPath.stream().mapToDouble(p -> p.getLongitude().doubleValue()).min().orElse(0);
        double maxLon = flightPath.stream().mapToDouble(p -> p.getLongitude().doubleValue()).max().orElse(0);
        
        // 创建矩形边界（按照KML规范的顺序）
        List<CoordinatePointReq> boundary = new ArrayList<>();
        boundary.add(createCoordinatePoint(minLat, minLon, 0)); // 左下
        boundary.add(createCoordinatePoint(minLat, maxLon, 0)); // 右下
        boundary.add(createCoordinatePoint(maxLat, maxLon, 0)); // 右上
        boundary.add(createCoordinatePoint(maxLat, minLon, 0)); // 左上
        boundary.add(createCoordinatePoint(minLat, minLon, 0)); // 闭合多边形
        
        return boundary;
    }
    
    /**
     * 确保边界多边形闭合
     * 如果第一个点和最后一个点不同，则添加第一个点到末尾
     */
    private static List<CoordinatePointReq> ensureBoundaryClosure(List<CoordinatePointReq> originalBoundary) {
        if (originalBoundary == null || originalBoundary.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<CoordinatePointReq> closedBoundary = new ArrayList<>(originalBoundary);
        
        // 检查是否闭合（第一个点和最后一个点是否相同）
        if (closedBoundary.size() > 2) {
            CoordinatePointReq firstPoint = closedBoundary.get(0);
            CoordinatePointReq lastPoint = closedBoundary.get(closedBoundary.size() - 1);
            
            // 判断坐标是否相同（允许微小误差）
            double latDiff = Math.abs(firstPoint.getLatitude().doubleValue() - lastPoint.getLatitude().doubleValue());
            double lonDiff = Math.abs(firstPoint.getLongitude().doubleValue() - lastPoint.getLongitude().doubleValue());
            
            // 如果第一个点和最后一个点距离大于0.000001度（约1米），则认为不闭合
            if (latDiff > 0.000001 || lonDiff > 0.000001) {
                // 添加第一个点到末尾以闭合多边形
                CoordinatePointReq closingPoint = createCoordinatePoint(
                    firstPoint.getLatitude().doubleValue(),
                    firstPoint.getLongitude().doubleValue(),
                    firstPoint.getHeight().doubleValue()
                );
                closedBoundary.add(closingPoint);
                System.out.println("✓ 边界多边形自动闭合，添加闭合点");
            }
        }
        
        return closedBoundary;
    }
    
    /**
     * 创建坐标点
     */
    private static CoordinatePointReq createCoordinatePoint(double lat, double lon, double height) {
        CoordinatePointReq point = new CoordinatePointReq();
        point.setLatitude(new BigDecimal(lat));
        point.setLongitude(new BigDecimal(lon));
        point.setHeight(new BigDecimal(height));
        return point;
    }
    
    /**
     * 转换坐标系（单个点）
     * 
     * @param point 原始坐标点
     * @param sourceSystem 源坐标系（GCJ02, WGS84, BD09）
     * @param targetSystem 目标坐标系（GCJ02, WGS84, BD09）
     * @return 转换后的坐标点
     */
    private static CoordinatePointReq convertCoordinateSystem(
            CoordinatePointReq point, 
            String sourceSystem, 
            String targetSystem) {
        
        // 如果源和目标坐标系相同，直接返回副本
        if (sourceSystem.equals(targetSystem)) {
            return createCoordinatePoint(
                point.getLatitude().doubleValue(),
                point.getLongitude().doubleValue(),
                point.getHeight().doubleValue()
            );
        }
        
        BigDecimal lat = point.getLatitude();
        BigDecimal lon = point.getLongitude();
        CoordinateTransformUtil.Coordinate convertedCoord = null;
        
        // 执行坐标系转换
        if ("GCJ02".equals(sourceSystem) && "WGS84".equals(targetSystem)) {
            // 高德坐标转GPS坐标
            convertedCoord = CoordinateTransformUtil.gcj02ToWgs84(lon, lat);
        } else if ("WGS84".equals(sourceSystem) && "GCJ02".equals(targetSystem)) {
            // GPS坐标转高德坐标
            convertedCoord = CoordinateTransformUtil.wgs84ToGcj02(lon, lat);
        } else if ("GCJ02".equals(sourceSystem) && "BD09".equals(targetSystem)) {
            // 高德坐标转百度坐标
            convertedCoord = CoordinateTransformUtil.gcj02ToBd09(lon, lat);
        } else if ("BD09".equals(sourceSystem) && "GCJ02".equals(targetSystem)) {
            // 百度坐标转高德坐标
            convertedCoord = CoordinateTransformUtil.bd09ToGcj02(lon, lat);
        } else if ("BD09".equals(sourceSystem) && "WGS84".equals(targetSystem)) {
            // 百度坐标转GPS坐标
            convertedCoord = CoordinateTransformUtil.bd09ToWgs84(lon, lat);
        } else if ("WGS84".equals(sourceSystem) && "BD09".equals(targetSystem)) {
            // GPS坐标转百度坐标
            convertedCoord = CoordinateTransformUtil.wgs84ToBd09(lon, lat);
        } else {
            throw new IllegalArgumentException(
                "不支持的坐标系转换: " + sourceSystem + " -> " + targetSystem);
        }
        
        return createCoordinatePoint(
            convertedCoord.getLatitude().doubleValue(),
            convertedCoord.getLongitude().doubleValue(),
            point.getHeight().doubleValue()
        );
    }
    
    /**
     * 转换坐标系（点列表）
     * 
     * @param points 原始坐标点列表
     * @param sourceSystem 源坐标系
     * @param targetSystem 目标坐标系
     * @return 转换后的坐标点列表
     */
    private static List<CoordinatePointReq> convertCoordinateSystemBatch(
            List<CoordinatePointReq> points, 
            String sourceSystem, 
            String targetSystem) {
        
        if (points == null || points.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 如果源和目标坐标系相同，直接返回副本
        if (sourceSystem.equals(targetSystem)) {
            return new ArrayList<>(points);
        }
        
        List<CoordinatePointReq> convertedPoints = new ArrayList<>();
        
        for (CoordinatePointReq point : points) {
            CoordinatePointReq convertedPoint = convertCoordinateSystem(point, sourceSystem, targetSystem);
            convertedPoints.add(convertedPoint);
        }
        
        System.out.println("✓ 坐标系转换完成: " + sourceSystem + " -> " + targetSystem + ", 点数: " + points.size());
        
        return convertedPoints;
    }
}